﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Hive.Core.Common.Shell;
using Hive.Core.Model;
using Hive.Core.Model.Commands;

namespace Hive.Core.ConsoleApplication
{
    /// <summary>
    /// The Hive program.
    /// </summary>
    public class HiveProgram
    {
        private readonly IHiveManager hiveManager;
        private readonly IShell shell;

        /// <summary>
        /// Creates a Hive program.
        /// </summary>
        /// <param name="hiveManager">The hive manager.</param>
        /// <param name="shell">The hive shell.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="hiveManager"/>
        /// or <paramref name="shell"/> is null.</exception>
        public HiveProgram(IHiveManager hiveManager, IShell shell)
        {
            if (hiveManager == null)
                throw new ArgumentNullException("hiveManager");
            if (shell == null)
                throw new ArgumentNullException("shell");

            this.hiveManager = hiveManager;
            this.shell = shell;
        }

        /// <summary>
        /// Runs the Hive program.
        /// </summary>
        /// <param name="args">The command-line arguments.</param>
        /// <returns>The exit code.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="args"/>
        /// is null or contains null.</exception>
        public CommandExitCode Run(string[] args)
        {
            try
            {
                var hiveArguments = HiveArguments.Parse(shell, args);
                if (hiveArguments == null)
                    return CommandExitCode.InvalidArguments;

                return RunInternal(hiveArguments);
            }
            catch (Exception ex)
            {
                shell.EchoException("A fatal exception occurred.", ex);
                return CommandExitCode.Exception;
            }
        }

        /// <summary>
        /// Runs the Hive program.
        /// </summary>
        /// <param name="hiveArguments">The hive arguments.</param>
        /// <returns>The exit code.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="hiveArguments"/> is null.</exception>
        public CommandExitCode Run(HiveArguments hiveArguments)
        {
            if (hiveArguments == null)
                throw new ArgumentNullException("hiveArguments");

            try
            {
                return RunInternal(hiveArguments);
            }
            catch (Exception ex)
            {
                shell.EchoException("A fatal exception occurred.", ex);
                return CommandExitCode.Exception;
            }
        }

        private CommandExitCode RunInternal(HiveArguments hiveArguments)
        {
            var command = hiveArguments.Command;

            Verbosity oldVerbosity = shell.Verbosity;
            try
            {
                shell.Verbosity = hiveArguments.Verbosity;
                return command.Execute(hiveManager, shell);
            }
            finally
            {
                shell.Verbosity = oldVerbosity;
            }
        }

        /// <summary>
        /// Runs the Hive program using the default hive manager and a console shell.
        /// </summary>
        /// <param name="args">The command-line arguments.</param>
        /// <returns>The exit code.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="args"/>
        /// is null or contains null.</exception>
        public static int Main(string[] args)
        {
            var shellOptions = new ConsoleShellOptions();

            using (var shell = new ConsoleShell(shellOptions))
            {
                    var hiveManager = new DefaultHiveManager();
                    var program = new HiveProgram(hiveManager, shell);
                    return (int)program.Run(args);
            }
        }
    }
}
